#include "glare.core.PlatformWindow.h"
#include "glare.gles2.Driver.h"

#include "Scene.01.HelloWindow.h"
#include "Scene.02.HelloTriangle.h"
#include "Scene.03.HelloIndexBuffer.h"
#include "Scene.04.HelloTexture.h"
#include "Scene.05.HelloCube.h"

#if GLARE_PLATFORM == GLARE_PLATFORM_WIN32
#	include "glare.d3d11.Driver.h"
#	include "glare.core.Win32Window.h"
#	define LOGW(...)
#elif GLARE_PLATFORM == GLARE_PLATFORM_ANDROID
#	include <android/log.h>
#	include "android_native_app_glue.h"
#	include "glare.core.Log.h"
#	include "glare.core.AndroidWindow.h"

#	define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "Glare3D.DemoBrowser", __VA_ARGS__))
#	define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "Glare3D.DemoBrowser", __VA_ARGS__))
#endif

using namespace Glare;

#if GLARE_PLATFORM == GLARE_PLATFORM_ANDROID
class DemoBrowserLog : public Log
{
public : virtual void LogMessage(const string& message, const LogMessageType& message_type) 
		 {
			 switch (message_type)
			 {
			 case LMT_Warning:
				 LOGW(message.c_str());
				 break;

			 case LMT_Error:
				 __android_log_print(ANDROID_LOG_ERROR, "Glare3D.DemoBrowser", message.c_str());
				 break;

			 default:
				 __android_log_print(ANDROID_LOG_WARN, "Glare3D.DemoBrowser", message.c_str());
				 break;
			 }
		 }
};
#elif GLARE_PLATFORM == GLARE_PLATFORM_WIN32
class DemoBrowserLog : public Log
{
public : virtual void LogMessage(const string& message, const LogMessageType& message_type) 
		 {
			 if (message_type != LMT_Error)
			 {
				 OutputDebugString((message + "\n").c_str());
				 return;
			 }

			 MessageBox(0, message.c_str(), "Error", 0);
		 }
};
#endif

#define ACTIVE_SCENE HelloCube

class Browser
{
public : Browser() 
			 : _driver(NULL)
			 , _scene(NULL)
			 , _platform_window(NULL)
		 {

		 }

public : void Initialize(PlatformWindow::ConstructionParams* wnd_params)
		 {
			 _platform_window = PlatformWindow::CreateDefaultWindow(800, 600, wnd_params);

			 //_driver = new D3D11Driver();
			 _driver = new GLES2Driver();
			 _driver->SetLog(&_log);
		 }

public : void Shutdown()
		 {
			 delete _platform_window;
			 _platform_window = NULL;

			 delete _driver;
			 _driver = NULL;
		 }

public : void SetScene(DemoScene* scene)
		 {
			 DestroyScene();

			 _scene = scene;
			 _scene->Initialize(_driver, _platform_window);
		 }

public : void DrawScene()
		 {
			 if (_scene)
				 _scene->DrawFrame();
		 }

public : void DestroyScene()
		 {
			 if (_scene)
			 {
				 _scene->Destroy();
				 delete _scene;
				 _scene = NULL;
			 }
		 }

private : DemoBrowserLog _log;
private : Driver* _driver;
private : DemoScene* _scene;
private : PlatformWindow* _platform_window;
};

Browser* browser;
DemoScene* scene;

#if GLARE_PLATFORM == GLARE_PLATFORM_WIN32

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
	MSG msg = {0};
	browser = new Browser();

	Win32WindowConstructionParams* w32_params = new Win32WindowConstructionParams();
	w32_params->InstanceHandle = (uint)GetModuleHandle(NULL);
	w32_params->Class = "glare_window_class";
	w32_params->Title = "Glare3D - Demo.Browser";

	browser->Initialize(w32_params);

	scene = new ACTIVE_SCENE();
	browser->SetScene(scene);

	// Main message loop
	while (msg.message != WM_QUIT)
	{
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else
		{
			browser->DrawScene();
		}
	}

	browser->DestroyScene();
	browser->Shutdown();

	delete browser;
	browser = NULL;
	scene = NULL;
}

#elif GLARE_PLATFORM == GLARE_PLATFORM_ANDROID

bool android_focused = true;

void android_shutdown()
{
	if (browser)
	{
		browser->DestroyScene();
		browser->Shutdown();
	}

	delete browser;
	browser = NULL;
	scene = NULL;

	android_focused = false;
}

static void HandleCmd(struct android_app* app, int32_t cmd)
{
	switch (cmd)
	{
	case APP_CMD_SAVE_STATE:
		// The system has asked us to save our current state.  Do so.
		break;

	case APP_CMD_INIT_WINDOW:
		if (app->window != NULL)
		{
			browser = new Browser();

			AndroidWindowConstructionParams* droid_params = new AndroidWindowConstructionParams();
			droid_params->NativeWindow = app->window;

			browser->Initialize(droid_params);

			scene = new ACTIVE_SCENE();
			browser->SetScene(scene);
		}
		break;

	case APP_CMD_TERM_WINDOW:
		android_shutdown();
		break;

	case APP_CMD_GAINED_FOCUS:
		android_focused = true;
		break;

	case APP_CMD_LOST_FOCUS:
		android_focused = false;
		break;
	}
}

void android_main(struct android_app* state)
{
	// make sure glue isn't stripped.
	app_dummy();

	state->onAppCmd = HandleCmd;

	while (true)
	{
		int ident;
		int events;
		struct android_poll_source* source;

		while ((ident = ALooper_pollAll(android_focused ? 0 : -1, NULL, &events, (void**)&source)) >= 0)
		{
			if (source != NULL)
				source->process(state, source);

			if (state->destroyRequested)
			{
				android_shutdown();
				return;
			}
		}

		if (browser)
			browser->DrawScene();
	}
}

#endif
